home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Environments / CGIshell 1.3.2 / samples / server.4th < prev   
Encoding:
Text File  |  1996-04-23  |  15.7 KB  |  434 lines  |  [TEXT/ALFA]

  1. \
  2. \
  3. \  PF Forms Handler Shell  --  Web Server Interface, version 1.3.2
  4. \
  5. \
  6. \  (c) Ronald T. Kneusel, 1995, 1996
  7. \  (rkneusel@post.its.mcw.edu)
  8. \
  9. \  This code may be used and distributed freely provided the copyright 
  10. \  notice remains intact and my name is mentioned in the documentation.
  11. \
  12. \  Last mod: 23-Apr-96
  13. \  =========================================================================
  14. \
  15. \  Provides a shell for writing CGI applications for use with WebSTAR.  The
  16. \  shell will handle all communication between WebSTAR and the CGI.  It also
  17. \  provides a vocabulary for extracting the information presented by WebSTAR.
  18. \
  19. \
  20. \  @Field ( addr1 addr2 new|append -- )
  21. \
  22. \      Get the post data string for the field whose address is
  23. \      on the stack.  Place the data into the string at addr2.  @Field 
  24. \      will convert characters as necessary.
  25. \
  26. \  @Addr ( addr new|append -- )
  27. \
  28. \      Put the client's IP address in the string at addr
  29. \
  30. \  @Direct ( addr new|append -- )
  31. \
  32. \      Put the direct argument in the string at addr
  33. \
  34. \  @Browser ( addr new|append -- )
  35. \
  36. \      Put the browser type in the string at addr
  37. \
  38. \  REPLY ( addr -- )
  39. \
  40. \      Send the string back to WebSTAR.  Use only within  ae: ... ;ae
  41. \
  42.  
  43. ( yet more disk I/O words by C. Heilman )
  44.  
  45. \ create space for the fcb and a word to access it
  46. variable FCB 78 allot  ( our File's Control Block )
  47. : +FCB ( offset -- addr ) fcb + ;  ( offset into fcb )
  48.  
  49. \ setup for a (register based) file manager toolbox call
  50. : FTRAP ( -- ) fcb >abs  ,$ 205E ;  ( movea.l [ps]+,a0 )
  51.  
  52. : CLOSE ( -- ) ftrap ,$ A001  ftrap ,$ A013 ;  ( _Close & _FlushBuffer )
  53. : ?DERROR ( -- ) \ report error if result is not zero
  54.     16 +fcb @ ?dup IF  ." DiskError" .  close  abort THEN ;
  55.  
  56. \ open a file with the address of a string of the pathname on the stack
  57. : OPEN ( addr -- ) \ addr is a Forth style string - str[255]
  58.     fcb 80 0 fill           \   clear the fcb for a new file
  59.     >abs  18 +fcb  2!        \  set name of the file to string
  60.     ftrap ,$ A000  ?derror ;  \ _Open the file in the fcb
  61.  
  62. \ create a file
  63. : NEWFILE ( name.addr -- )
  64.     fcb 80 0 fill           \   clear the fcb for a new file
  65.     >abs  18 +fcb  2!        \  set name of the file to string
  66.     ftrap ,$ A008  ?derror    ( _Create )
  67.     ,s TEXT 32 +fcb 2!         \ TEXT type
  68.     ftrap ,$ A00D ?derror ;   ( _SetFileInfo )
  69.  
  70. \ return the filesize !!! MUST BE <32K !!!
  71. : @SIZE ( -- bytes ) ftrap ,$ A011  30 +fcb @ ;  ( _GetEOF )
  72.  
  73. \ set some fcb parameters
  74. : !SIZE ( bytes -- ) 38 +fcb ! ;      \ set bytes-to-read/write
  75. : !BUFF ( addr -- ) >abs 32 +fcb 2! ;  \ set read/write buffer pointer
  76.  
  77. \ read/write with buffer addr and bytes to read/write on the stack
  78. : READ ( addr count -- )  !size !buff ftrap ,$ A002  ?derror ;  ( _Read )
  79. : WRITE ( addr count -- ) !size !buff ftrap ,$ A003  ?derror ;  ( _Write )
  80.  
  81. \ read/write file a byte at a time to/from the stack
  82. : GETCHR ( -- c ) here 1 read  here c@ ;
  83. : PUTCHR ( c -- ) here c!  here 1 write ;
  84.  
  85. \ read until character (c) is encountered
  86. : CREAD ( addr c -- bytes_read )
  87.     44 +fcb c!  128 45 +fcb c!  \ setup ioPosMode
  88.     @SIZE read  42 +fcb @ ;     \ put lowbyte of ioActCount on stack
  89.  
  90. \ A defining word for strings
  91. : $[  \ compiling: ( -- ) enclose a ] terminated string
  92.     CREATE  93 word here  c@ 1+ dup 2 mod +  allot
  93.     DOES>  ;  \ runtime action: ( -- addr ) \ <<-- no count!
  94.  
  95. ( end I/O words )
  96.  
  97.  
  98. ( *************************** String Functions **************************** )
  99. ( Strings 10/15/95 23:30:19 )
  100. \ These words deal with 0 terminated strings.
  101. \
  102. \ The names maintain compatability with the word-set in
  103. \  _Library of Forth Routines and Utilities_  by  James D. Terry
  104. \  (c) 1986 Shadow Lawn Press  ISBN 0-452-25841-3
  105. \
  106. \ In comments, string is the starting address of a zero terminated string,
  107. \ and len is the length not including the zero. String[255] is a length
  108. \ byte preceded string, with a max length of 255 bytes.
  109. \
  110. \ String format:
  111. \ string address is first byte ->This is a string.0<- Ends with a zero
  112.  
  113. \ *** Most of these routines written by C. Heilman ***
  114.  
  115. \ Length and $clear get used a lot - do them in ml.
  116. : LENGTH ( string -- len )  \ length of the string at addr
  117.  ( was:  dup >r BEGIN dup c@ WHILE 1+ REPEAT  r> - ; )
  118.     ,$ 3016          \     move (ps),d0
  119.     ,$ 4a33 ,$ 0000  \ @0: tst.b 0(bp,d0.w)
  120.     ,$ 6706          \     beq.s @1
  121.     ,$ 0640 ,$ 0001  \     addi #1,d0
  122.     ,$ 60f4          \     bra.s @0
  123.     ,$ 9056          \ @1: sub (ps),d0
  124.     ,$ 3c80 ;        \     move d0,(ps)
  125.  
  126. : $CLEAR  ( string -- ) \ erase a string ( equivalent to: 0 swap c! ; )
  127.    ,$ 301E  ,$ 4233 ,$ 0000 ;  \ move (ps)+,d0  clr.b 0(bp,d0.w)
  128.  
  129. \ The next 4 words are directly from Ron's CGI Framework.
  130.  
  131. \ Convert between null terminated and length byte preceeded type strings.
  132. : >NULL ( string[255] -- )  \ convert a string[255] into a string
  133.     dup c@ 2dup + >r swap dup 1+ swap rot cmove  r> $clear ;
  134.  
  135. : >COUNT ( string -- ) \ convert a string into a string[255]
  136.     dup length >r dup dup 1+ r cmove  r> swap c! ;  
  137.  
  138.  
  139. \ Terminal I/O.
  140. : 0TYPE ( string -- )  \ type null terminated string
  141.     dup length dup IF type ELSE 2drop THEN ;
  142.     
  143. : ACCEPT ( string len -- )  \ like expect but stores zero at end of line
  144.     2dup 1+ 0 fill  >r dup r> expect dup length 1- + $clear ; ( bug fixed)
  145.  
  146.  
  147. \ Test a string's content.
  148. : $= ( string1 string2 -- f ) \ true if string2,len2 = string1,len1
  149.     dup length 1+  -1 swap 2swap rot 0 DO  \ set flag to true
  150.       over r + c@  over r + c@  =         \  check each byte
  151.       0= IF rot 1+ rot rot leave THEN    \   change flag to false
  152.     LOOP 2drop ;
  153.  
  154.  
  155. \ Manipulate strings.
  156. : $COPY ( source.string dest.string -- ) \ copy source to dest
  157.     over length 1+ cmove ;
  158.  
  159. : $+ ( source.string dest.string -- ) \ append source to the end of dest
  160.     dup length + $copy ;
  161.  
  162. : $LEFT ( string len -- ) \ clip string to len chars
  163.     over length min  +  $clear ;
  164.  
  165. : $RIGHT ( string len -- ) \ clip string to rightmost len characters
  166.     over length over - 0> IF
  167.       over length over -  rot dup rot +  swap rot 1+  cmove
  168.     ELSE 2drop THEN ;
  169.  
  170. : $MID ( string start len -- ) \ clip string to len section at start
  171.     rot rot over length  swap - 1+  >r dup r> $right  swap $left ;
  172.  
  173. : $UPPER ( string -- ) dup >count  dup upper  dup >null drop ; \ uppercase
  174.  
  175. : $CHAR ( character string -- ) dup length + dup >r c! 0 r> 1+ c! ;
  176.  
  177.  
  178. \ Find and replace with strings.
  179. variable POS  ( local variable )
  180. : $FIND ( string1 string2 -- pos ) \ find string2 in string1; 0 if unfound
  181.     0 pos !
  182.     over length over length - 2+  1  DO
  183.       over here $copy
  184.       here  over length  r swap  $mid
  185.       here over
  186.       $= IF  r pos !  leave THEN
  187.     LOOP  2drop
  188.     pos @ ;
  189.  
  190. : $REPLACE ( dest.string1 find.string2 replace.string3 -- )
  191.     rot >r swap
  192.     r over $find ?dup IF  \   IF string2 is found in string1
  193.       r here $copy         \  THEN replace string2 with string3
  194.       r over 1-  $left      \  modify string1
  195.       rot r $+
  196.       swap length +           \        !!! IMPORTANT !!!
  197.       here length  swap - 1+   \   DOES NOT CHECK FOR OVERWRITE
  198.       here swap $right          \  String1 MUST accomodate any
  199.       here r> $+                 \ additional bytes from string3
  200.     ELSE 2drop r> drop  THEN ;
  201.  
  202. \ Create and assign strings of several varieties.
  203. : $CONSTANT  \ compiling: ( -- ) name a string terminated with '}'
  204.     CREATE  125 word here c@ 1+ dup 2 mod + allot  0 [compile] ,
  205.     DOES>  count drop ;  \ runtime action: ( -- string )
  206. \ This uses a curley brace because they aren't used much on web pages.
  207. \   eg:  $constant ESERROR Empty stack!}
  208.  
  209. : $VARIABLE CREATE 1+ allot ;  \ compiling: ( len -- ) name an empty string
  210. \   eg:  80 $variable INPUTLINE  inputline ${ Hi there!}
  211.  
  212. : $ARRAY \ create named string arrays - name from input stream
  213.     CREATE  dup ,  * allot    \ compiling: ( number_of_.strings len -- )
  214.     DOES>  dup @ rot * + 2+ ;  \ runtime: ( string_number -- string )
  215. \   eg:  15 64 $array ERRORMESSAGES
  216. \        0 errorMessages ${ Error!}
  217.  
  218. \ NOTE: Constants and variables are identical except that constants
  219. \       have no room to grow, but variables _may_ have extra memory
  220. \       allotted to them to grow into.  Also constants are assigned
  221. \       when they are created, while variables (and arrays, which are
  222. \       lists of variables) must be assigned seperately (see below).
  223.  
  224. : ${ ( string -- ) \ assign text to a string from the input stream.
  225.     125 word  here >null  here swap $copy ;
  226. \   eg:  inputLine ${ Something to say!}    *** NO OVERWRITE CHECK ***
  227.  
  228. : MESSAGE[  \ compiling: ( -- ) enclose subsequent ']'ed string
  229.     CREATE  93 word here  c@ 1+ dup 2 mod +  allot  0 [compile] ,
  230.     DOES>  count drop ;  \ runtime action: ( -- addr )
  231.  
  232. : STRING>>  \ compiling: ( n -- )  number of bytes in the string
  233.     CREATE  allot ;
  234.     
  235. : <> = 0= ; macro
  236.  
  237. : newstr  ( addr -- )  \ zero a string
  238.    0 swap c! ;
  239.  
  240. : strcpy ( str1 str2 -- ) \ copy string 1 to string 2
  241.     dup length + >r  \ automatically append
  242.     BEGIN  dup c@ 0 <>  WHILE
  243.       dup c@ r c!  r> 1+ >r  1+
  244.     REPEAT  0 r> c!  ;
  245.  
  246. : strncpy ( str1 str2 -- ) \ copy as above, clear str2 first
  247.     dup newstr  strcpy ;
  248.  
  249. : 0type ( addr -- )  \ type null terminated string
  250.     dup length dup 0 <> IF type ELSE 2drop THEN ;
  251.     
  252. : >null ( addr -- )  \ convert a counted string into a null terminated string
  253.     dup c@ 2dup + >r swap dup 1+ swap rot cmove  0 r> c! ;
  254.  
  255. : >count ( addr -- ) \ convert a null terminated string into a counted string
  256.     dup length >r dup dup 1+ r cmove  r> swap c! ;  
  257.  
  258. : accept ( addr len -- )  \ like expect but no blank at end of line
  259.     swap dup >r swap expect  0 r r> length 1- c! ;
  260.  
  261.  
  262. ( **************** Apple Event and reply string handler ******************* )
  263.  
  264. \ This code courtesy of C. Heilman, slight mods RTK
  265.  
  266. 2variable DDATA  4 allot
  267.  
  268. MESSAGE[ SERROR  Empty stack!]
  269.  
  270. ( get AEDesc handle from an Apple Event )
  271. : ?DESC ( d.key d.type -- desc.handle desc.type -1  or  0 )
  272.     0 >r                                  ( room for error        )
  273.     202 +md 2@ 2>r                        ( the AppleEvent handle )
  274.     2swap 2>r  2>r                        ( keyword and type      )
  275.     here a>r                              ( receiving address     )
  276.     ,$ 303C ,$ 812 ,$ A816 ( AEGetParamDesc: move #$812,d0 _Pack8 )
  277.     r> 0= IF                              ( if there is no error  )
  278.       here 4 + 2@  here 2@  -1            ( get data & leave true )
  279.     ELSE  0 THEN ;                        ( or else leave false   )
  280.  
  281. : -DESC ( addr.where.desc.is.stored -- error ) ( remove desc rec. )
  282.     0 >r  a>r                          ( push room and descriptor )
  283.    ,$ 303C ,$ 0204 ,$ A816 ( AEDisposeDesc: move #$0204,d0 _Pack8 )
  284.     r> ;
  285.  
  286. 2variable DSIZE  \ this double variable holds the size of a string in dbuff
  287. variable  DBUFF 4094 allot  \ this block is filled with a text string
  288.  
  289. ( get AE data from an Apple Event )
  290. : ?DATA ( d.key -- addr  -1  or  0 )
  291.     0 >r               \ make room on stack for error
  292.     202 +md 2@ 2>r      \ push theAppleEvent address
  293.     2>r  ,s TEXT 2>r     \ push keyword (from pstack) and desired type (TEXT)
  294.     here a>r              \ push an address to hold the actual type
  295.     dbuff a>r              \ push the data receiving address
  296.     4096 s>d 2>r            \ max number of bytes to read
  297.     dsize a>r                \ push a variable to hold the actual size
  298.     ,$ 303C ,$ 0E11 ,$ A816   \ AEGetParamPtr: move #$812,d0 _Pack8
  299.     r> 0= IF                   \ if there is no error
  300. \      dbuff  dsize 2@ drop  -1  \ put address, count and true on pstack
  301.        0 dbuff dsize 2@
  302.        drop + c!  dbuff -1      \ make null terminated 
  303.     ELSE  0 THEN ;               \ else false
  304.  
  305. \ Reply to an Apple Event with a string
  306. : REPLY ( addr -- )  \ **** USE INSIDE OF A HANDLER ONLY ****
  307.     dup length                \ how long is it?
  308.     0 >r                      \ put room for error on rstack
  309.     198 +md 2@ 2>r            \ put the ReplyEvent handle on rstack
  310.     ,s ---- 2>r  ,s TEXT 2>r  \ put keyword and type on rstack
  311.     swap a>r  0 2>r           \ put addr & count on rs from pstack
  312.     ,$ 303C ,$ 0A0F ,$ A816   \ AEPutParamPtr: move #$A0F,d0 _Pack8
  313.     r> drop ;                 \ ignore any error
  314.  
  315.  
  316. ( ******************* Words to get field data *********************** )
  317.  
  318.  0 constant NEW     \ start a new string
  319. -1 constant APPEND  \ append at end of existing string
  320.  
  321. variable theAddr    \ holds the address of the string
  322.  
  323. : zeroStr ( -- )  \ zero the string in theAddr
  324.    0 theAddr @  c! ;
  325.  
  326. : >append ( c -- )  \ put a character on the end of theAddr
  327.    theAddr @ length  theAddr @ + dup >r c!     \ character
  328.    0 r> 1+ c! ;  \ null
  329.  
  330. : count>str  ( addr len -- )  \ copy characters into the string
  331.    >r dup r> + swap DO
  332.      r c@ >append
  333.    LOOP ;
  334.  
  335. variable <str>  \ address of target string
  336.  
  337. : h>d ( c -- d )  \ hex digit to decimal, no error checking
  338.    dup 64 > IF  55 -  ELSE  48 -  THEN ;
  339.  
  340. : hex>char ( addr --  )  \ convert a %xx sequence into a character
  341.    1+ dup c@  swap  1+ c@
  342.    h>d swap h>d 16 * +
  343.    dup 32 < IF
  344.      13 = IF  13 <str> @ $CHAR THEN  \ return character
  345.    ELSE
  346.      <str> @ $CHAR  \ anything >= space
  347.    THEN
  348. ;
  349.  
  350. : $copy+ ( s1 len s2 -- )  \ copy s1 to s2 changing %nn codes to characters
  351.    <str> !  \ keep address of target string
  352.    swap dup rot + swap DO
  353.      r c@
  354.      dup 43 = IF  drop  32 <str> @ $CHAR  1  ELSE  \ '+' to space
  355.      dup 37 = IF  drop  r hex>char 3         ELSE  \ %xx
  356.      <str> @ $CHAR  1 THEN THEN                    \ alphanumeric character
  357.    +LOOP
  358. ;
  359.  
  360. create ~cr  3 allot  13 ~cr c! 10 ~cr 1+ c!  0 ~cr 2+ c!
  361. : +crlf  ~cr swap strcpy ;   \ add a <cr><lf> pair
  362.  
  363. message[ rt0 <html>]
  364. message[ rt1 </html>]
  365.  
  366. : startString ( addr -- )  ( load the header text into string ) 
  367.    rt0 swap strcpy ;
  368. : endString ( addr -- ) rt1 swap strcpy ;  ( ending text )
  369.  
  370. ( *************************** Number <--> String ************************* )
  371.  
  372. : f>str ( f addr -- )   \ convert a float to a string in addr
  373.     depth 4 > IF   \ original CH, modified by RTK
  374.       theAddr !  zeroStr \ dest address
  375.       @pen 2>r  10 +md @ >r  30000 10 +md ! \ move pen offscreen
  376.       3000 3000 !pen f.         \ print float: string is at here
  377.       r> 10 +md !  2r> !pen     \ return pen to origonal position
  378.       here count count>str      \ put it addr
  379.     ELSE serror THEN ;
  380.  
  381. create b#! 80 allot  \ buffer for string conversion
  382. : str>f ( addr -- f )  \ convert a string into a float
  383.    dup >r b#! r> length 1+ cmove   \ move to buffer
  384.    b#! 1- >abs fnumber ;  \ and convert
  385.  
  386. ( ********************** User level words ************************* )
  387.  
  388. : @Direct ( addr new|append -- )  \ get the direct argument
  389.    swap theAddr !   \ store the string address
  390.    NEW = IF zeroStr THEN  \ clear the string
  391.    ,s ---- ?data IF  theAddr @ $+  THEN  \ get the argument
  392. ;
  393.  
  394. : @Addr  ( addr new|append -- )  \ get the IP address
  395.    swap theAddr !   \ store the string address
  396.    NEW = IF zeroStr THEN  \ clear the string
  397.    ,s addr ?data IF theAddr @ $+  THEN  \ get it
  398. ;
  399.  
  400. : @Browser ( addr new|append -- )  \ get the browser type
  401.    swap theAddr !   \ store string address
  402.    NEW = IF zeroStr THEN
  403.    ,s Agnt ?data IF  theAddr @ $+  THEN  \ get it
  404. ;
  405.  
  406. variable $fld   \ holds field name
  407. variable $adr   \ holds address
  408. variable $out   \ holds output string
  409. message[ & &]  \ end of field data marker
  410.  
  411. : @Field ( addr1 addr2 new|append -- ) \ get the data for a field
  412.    NEW = IF  swap dup $CLEAR swap  THEN
  413.    $fld !          \ address of field name string
  414.    61 $fld @ $CHAR  \ add an "="
  415.    $out !   \ address of output string
  416.    ,s post ?data IF  \ there is post data
  417.      $adr !
  418.      $adr @ $fld @ $FIND dup 0= IF
  419.        drop         \ no field data
  420.        0 $out @ c!  \ empty string
  421.      ELSE
  422.        1- $fld @ length + $adr @ + \ found the field
  423.        dup & $FIND dup 0= IF
  424.           drop dup length      \ end of string
  425.        ELSE 1- THEN            \ not end of string
  426.        $out @ $copy+           \ put it in the string
  427.      THEN
  428.    THEN
  429.    0 $fld @ dup length 1- + c!  \ remove "="
  430. ;
  431.  
  432. \ on to field.4th
  433.